這天把「人類+AI」接進你已經成形的開發骨架:用一鍵化腳本把 AI 能做的事變成可靠重複的流程,用守門規則擋住 AI 產出的各種翻車現場。所有東西都要能在本地、CI、容器裡跑出同樣結果,這是前 28 天的共同語言。Hatch/Nox 一鍵化、鎖檔與可重現建置、型別與契約測、安全掃描與授權治理、觀測指標與追蹤都會被串起來。
AI 參與的開發活動大致分三類:
原則只有一條:把這些行為變成「可被腳本呼叫」的任務,塞進 Hatch/Nox 的單一入口,讓所有人用同一顆按鈕啟動它。
在 pyproject.toml
增加 AI 助攻的腳本群組,遵循我們既有的「一鍵多工」寫法【】:
[tool.hatch.envs.dev]
features = ["dev"] # 你既有的開發 extra:pytest/ruff/black/mypy...
[tool.hatch.envs.dev.scripts]
check = [
"ruff check .",
"black --check .",
"mypy src/",
"pytest -q"
]
# --- AI 協作:全部「可選、可重演、可審計」 ---
ai:review = "python -m scripts.ai_review --diff HEAD"
ai:doc = "python -m scripts.ai_doc --paths src/"
ai:changelog = "python -m scripts.ai_changelog --since-tag $(git describe --tags --abbrev=0)"
noxfile.py
保持跨版本驗證,讓 AI 產物也走同一條 CI 流程路徑【】:
import nox
@nox.session(python=["3.10","3.11","3.12"])
def ai(session):
session.install(".[dev]") # 用你既有的 dev extra
session.run("python","-m","scripts.ai_review","--sample")
重點:AI 腳本必須是純 Python/CLI,輸入固定、輸出可重演,避免「每次跑都長不一樣」的玄學。
延續 Day 10 的型別守門【】,再加三把刀:
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
# 1) 禁止把 AI 產生的 Placeholder 混進 PR
- id: forbid-ai-placeholders
name: forbid ai placeholders
entry: python scripts/gates/forbid_ai_placeholders.py
language: system
pass_filenames: true
# 2) 文字/程式碼都要有規範格式
- id: ruff
name: ruff
entry: ruff check .
language: system
pass_filenames: false
- id: black
name: black
entry: black --check .
language: system
pass_filenames: false
# 3) 型別守門(Day 10)
- id: pyright
name: pyright
entry: pyright
language: system
pass_filenames: false
- id: mypy
name: mypy
entry: mypy
language: system
pass_filenames: false
forbid_ai_placeholders.py
的檢查邏輯很無情也很有效:擋住 TODO/???/FIXME
、「Generated by」「LLM」「示意用」等關鍵字與可疑檔頭,避免把未審核的自動產物直接合進主幹。
在的 hatch run ci
維持統一入口,於 CI job 增加「AI 結果一致性」與「安全治理」步驟,與掃描並排:
# ci.yml 片段
- name: AI review (idempotent)
run: |
uv run hatch run dev:ai:review --diff HEAD~1..HEAD --save .reports/ai_review.json
test -s .reports/ai_review.json # 有輸出才算過
- name: Security & license
run: |
uv run hatch run sec:check-all # 延續 Day 26 的腳本組合
保持多階段建置,把「鎖檔」「非 root」「stdout JSON log」原則不變。AI 腳本若在 build 階段需要跑,務必使用 uv.lock
與 --frozen
同步依賴,避免不同鏡像生成不同結果。
這些腳本只做「提案」,不做「修改」。最後的決策仍由人類與傳統檢查來判定,與我們既有的型別/測試/安全守門一起工作,而不是互相取代。
scripts/ai_review.py
:針對 diff 產生審查意見# 簡化版骨架:讀 diff -> 分段 -> 產 JSON 建議
# 真正的「模型調用」細節留白,確保可替換性(本地/雲端/代理皆可)
import json, subprocess, sys, re
def get_diff(spec="HEAD"):
return subprocess.check_output(["git","diff",spec]).decode()
def review_hints(patch:str)->list[dict]:
hints=[]
if re.search(r"except Exception:", patch):
hints.append({"severity":"warn","rule":"broad-except",
"msg":"避免捕太廣,改成具體例外並記錄 trace_id。"})
if "print(" in patch:
hints.append({"severity":"info","rule":"logging",
"msg":"用 structlog 打 JSON,攜帶 trace_id/span_id。【觀測 Day28】"})
return hints
if __name__=="__main__":
diff = get_diff(sys.argv[sys.argv.index("--diff")+1] if "--diff" in sys.argv else "HEAD")
out = review_hints(diff)
print(json.dumps(out,ensure_ascii=False,indent=2))
提示裡刻意提醒用 JSON log 並攜帶 trace_id/span_id,對應整合做法。
scripts/ai_doc.py
:為模組與公開 API 產出 Docstring 草案src/
公開介面docs/_drafts/*.md
,不直接覆蓋原檔scripts/ai_changelog.py
:生成變更日誌初稿CHANGELOG.md
草稿TODO/???/FIXME/Generated by
的變更合併trace_id/span_id
,方便拉回整條追蹤hatch run
或 nox
觸發,不接受人肉命令差異hatch run dev:check
,hatch run dev:ai:review
hatch run ci
跑完整檢查矩陣與 AI 建議輸出,附 artifact症狀 | 可能原因 | 修法 |
---|---|---|
每次 AI 輸出結果都不一樣 | 腳本內隨機種子或非鎖定環境 | 固定 random seed,依賴走 uv.lock --frozen ,輸出成 JSON 並上傳 artifact 以比對 |
本地過、CI 不過 | 入口不一致或依賴不同 | 一律 hatch run /nox ,CI 先 uv sync --locked 再跑檢查 |
AI 建議忽略觀測欄位 | 程式碼沒帶追蹤上下文 | 先 setup OTel,再 setup logging,把 trace_id/span_id 注入 JSON log |
Vibe coding 的重點不是「讓 AI 幫你寫」,而是「讓團隊在同一條可重演的軌道上寫」。把 AI 收編進你既有的工程化骨架:單一入口、一致環境、嚴格守門、全程可觀測。當流程站穩,AI 只是多了一個聰明又會犯錯的實習生,出手快,但每次都要留下證據和紀錄。這就是 Day 29 要你帶走的節奏。